package com.kqb.auth.utils;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.JWTValidator;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.kqb.api.auth.bo.UserInfoInTokenBO;
import com.kqb.auth.constant.RedisConstant;
import com.kqb.auth.domain.vo.UserInfoTokenVo;
import com.kqb.common.core.utils.AjaxResult;
import com.kqb.common.redis.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 杉果树皮
 * @date 2025/4/10 20:06
 * @description: jwt
 */
@Component
public class JwtUtils {
    /**
     * 秘钥
     */
    private String secret = "123456789";

    /**
     * 认证令牌过期时间（默认30分钟）
     */
    private Long accessTokenExpiration = (long) 30 * 1000;

    /**
     * 刷新令牌过期时间（默认7天）
     */
    private Long refreshTokenExpiration = (long) 60 * 60 * 1000 * 7;

    @Autowired
    RedisUtils redisUtils;

    /**
     * 生成认证令牌
     */
    public String generateAccessToken(UserInfoInTokenBO userInfoInTokenBO) {
        return JWT.create()
                .addHeaders(getHeader())
                .addPayloads(BeanUtil.beanToMap(userInfoInTokenBO))
                .setExpiresAt(getAccessExpireDate())
                .setKey(secret.getBytes()).sign();
    }

    /**
     * 生成刷新令牌
     */
    public String generateRefreshToken(UserInfoInTokenBO userInfoInTokenBO) {
        return JWT.create()
                .addHeaders(getHeader())
                .addPayloads(BeanUtil.beanToMap(userInfoInTokenBO))
                .setExpiresAt(getrefreshExpireDate())
                .setKey(secret.getBytes()).sign();
    }

    /**
     * 生成token 放入Redis 并返回给前端
     */
    public UserInfoTokenVo generateToken(UserInfoInTokenBO userInfoInTokenBO) {
        String accessToken = generateAccessToken(userInfoInTokenBO); //认证token
        String refreshToken = generateRefreshToken(userInfoInTokenBO); //刷新token

        UserInfoTokenVo userInfoTokenVo = new UserInfoTokenVo();
        userInfoTokenVo.setAccessToken(accessToken);
        userInfoTokenVo.setRefreshToken(refreshToken);
        userInfoTokenVo.setUserInfoInTokenBO(userInfoInTokenBO);
        // 1. 查看redis 是否存在 user_token:userId:sys 存在 删除  每次登录都要重新生成新的token
        String tokenPrefix = RedisConstant.USER_TOKEN + RedisConstant.COLON
                + userInfoInTokenBO.getUserId() + RedisConstant.COLON + userInfoInTokenBO.getSysType();
        Boolean del = redisUtils.del(tokenPrefix);
        // 2. user_token:userId:sys  accessToken:refreshToken 存入redis;
        redisUtils.setNx(tokenPrefix,
                accessToken + RedisConstant.COLON + refreshToken,
                refreshTokenExpiration
        );
        return userInfoTokenVo;


    }

// TODO: 2025/4/12 token校验

    /**
     * 验证解析token
     */
    public AjaxResult validateToken(String token) {

        // 1. 判断token是否为空
        if (StrUtil.isBlank(token)) {
            return AjaxResult.error("token not is blank or null");
        }
        try {
            // 2. 判断token有效
            JWTValidator.of(token).validateAlgorithm(JWTSignerUtil.hs256(secret.getBytes()));
        } catch (ValidateException e) {
            return AjaxResult.error(0, "token验证失败:" + e.getMessage());
        }
        try {
            // 3. 判断token是否过期
            JWTValidator.of(token).validateDate(DateUtil.date());
        } catch (ValidateException e) {
            //查看redis 刷新令牌
            return AjaxResult.error(2, "accessToken过期");
        }
        // 4. 获得用户信息
        JWT jwt = JWTUtil.parseToken(token);
        JWTPayload payload = jwt.getPayload();
        JSONObject entries = JSONUtil.parseObj(payload.toString());
        UserInfoInTokenBO userInfoInTokenBO = JSONUtil.toBean(entries, UserInfoInTokenBO.class);
        return AjaxResult.success(3, "token验证成功", userInfoInTokenBO);
    }

    /**
     * 获得 jwt header
     */
    private Map getHeader() {
        Map<String, String> map = new HashMap<>();
        map.put("typ", "JWT");
        map.put("alg", "HS256");
        return map;
    }

    /**
     * 获取accessToken过期时间
     */
    private Date getAccessExpireDate() {
        Date date = new Date(System.currentTimeMillis() + accessTokenExpiration);
        return date;
    }

    /**
     * 获取refreshToken 过期时间
     */
    private Date getrefreshExpireDate() {
        Date date = new Date(System.currentTimeMillis() + refreshTokenExpiration);
        return date;
    }

}
